#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据模型定义
包含学生、课程、成绩、用户等核心数据类
"""

import hashlib
from typing import Optional, List, Dict, Any
from dataclasses import dataclass, field
from datetime import datetime


@dataclass
class Course:
    """课程信息类"""
    course_id: str
    course_name: str
    credits: float
    teacher: str = ""
    
    def __post_init__(self):
        """数据验证"""
        if not self.course_id or not self.course_name:
            raise ValueError("课程代码和名称不能为空")
        if self.credits <= 0:
            raise ValueError("学分必须大于0")
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'course_id': self.course_id,
            'course_name': self.course_name,
            'credits': self.credits,
            'teacher': self.teacher
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Course':
        """从字典创建对象"""
        return cls(**data)
    
    def to_string(self) -> str:
        """将课程信息转换为字符串格式"""
        return f"{self.course_id},{self.course_name},{self.credits},{self.teacher}"
    
    @classmethod
    def from_string(cls, line: str) -> 'Course':
        """从字符串创建课程对象"""
        parts = line.strip().split(',')
        if len(parts) != 4:
            raise ValueError("课程数据格式错误")
        return cls(parts[0], parts[1], float(parts[2]), parts[3])
    
    def __str__(self):
        return f"课程代码: {self.course_id}, 课程名称: {self.course_name}, 学分: {self.credits}, 授课教师: {self.teacher}"


@dataclass
class Grade:
    """成绩信息类"""
    student_id: str
    course_id: str
    score: float
    semester: str
    exam_type: str = "期末考试"
    
    def __post_init__(self):
        """数据验证"""
        if not self.student_id or not self.course_id or not self.semester:
            raise ValueError("学号、课程代码和学期不能为空")
        if not (0 <= self.score <= 100):
            raise ValueError("成绩必须在0-100之间")
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'student_id': self.student_id,
            'course_id': self.course_id,
            'score': self.score,
            'semester': self.semester,
            'exam_type': self.exam_type
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Grade':
        """从字典创建对象"""
        return cls(**data)
    
    def to_string(self) -> str:
        """将成绩信息转换为字符串格式"""
        return f"{self.student_id},{self.course_id},{self.score},{self.semester},{self.exam_type}"
    
    @classmethod
    def from_string(cls, line: str) -> 'Grade':
        """从字符串创建成绩对象"""
        parts = line.strip().split(',')
        if len(parts) != 5:
            raise ValueError("成绩数据格式错误")
        return cls(parts[0], parts[1], float(parts[2]), parts[3], parts[4])
    
    def get_grade_point(self) -> float:
        """根据分数计算绩点"""
        grade_points = {
            (90, 100): 4.0,
            (85, 89): 3.7,
            (82, 84): 3.3,
            (78, 81): 3.0,
            (75, 77): 2.7,
            (72, 74): 2.3,
            (68, 71): 2.0,
            (64, 67): 1.5,
            (60, 63): 1.0
        }
        
        for (min_score, max_score), point in grade_points.items():
            if min_score <= self.score <= max_score:
                return point
        return 0.0
    
    def get_letter_grade(self) -> str:
        """根据分数获取等级"""
        if self.score >= 90:
            return "A"
        elif self.score >= 80:
            return "B"
        elif self.score >= 70:
            return "C"
        elif self.score >= 60:
            return "D"
        else:
            return "F"
    
    def __str__(self):
        return f"学号: {self.student_id}, 课程: {self.course_id}, 成绩: {self.score}, 学期: {self.semester}, 类型: {self.exam_type}"


@dataclass
class Student:
    """学生信息类"""
    student_id: str
    name: str
    age: int
    major: str
    class_name: str
    
    def __post_init__(self):
        """数据验证"""
        if not self.student_id or not self.name or not self.major or not self.class_name:
            raise ValueError("学号、姓名、专业和班级不能为空")
        if not (16 <= self.age <= 50):
            raise ValueError("年龄必须在16-50岁之间")
        if not (6 <= len(self.student_id) <= 10) or not self.student_id.isdigit():
            raise ValueError("学号格式错误")
        if not (2 <= len(self.name) <= 10):
            raise ValueError("姓名长度必须在2-10个字符之间")
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'student_id': self.student_id,
            'name': self.name,
            'age': self.age,
            'major': self.major,
            'class_name': self.class_name
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Student':
        """从字典创建对象"""
        return cls(**data)
    
    def to_string(self) -> str:
        """将学生信息转换为字符串格式"""
        return f"{self.student_id},{self.name},{self.age},{self.major},{self.class_name}"
    
    @classmethod
    def from_string(cls, line: str) -> 'Student':
        """从字符串创建学生对象"""
        parts = line.strip().split(',')
        if len(parts) != 5:
            raise ValueError("数据格式错误")
        return cls(parts[0], parts[1], int(parts[2]), parts[3], parts[4])
    
    def __str__(self):
        return f"学号: {self.student_id}, 姓名: {self.name}, 年龄: {self.age}, 专业: {self.major}, 班级: {self.class_name}"


@dataclass
class User:
    """用户类"""
    username: str
    password_hash: str
    role: str
    student_id: str = ""
    created_at: datetime = field(default_factory=datetime.now)
    last_login: Optional[datetime] = None
    
    def __post_init__(self):
        """数据验证"""
        if not self.username or not self.password_hash or not self.role:
            raise ValueError("用户名、密码和角色不能为空")
        if self.role not in ['admin', 'teacher', 'student']:
            raise ValueError("角色必须是 admin、teacher 或 student")
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'username': self.username,
            'password_hash': self.password_hash,
            'role': self.role,
            'student_id': self.student_id,
            'created_at': self.created_at.isoformat(),
            'last_login': self.last_login.isoformat() if self.last_login else None
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'User':
        """从字典创建对象"""
        data = data.copy()
        if 'created_at' in data and isinstance(data['created_at'], str):
            data['created_at'] = datetime.fromisoformat(data['created_at'])
        if 'last_login' in data and data['last_login'] and isinstance(data['last_login'], str):
            data['last_login'] = datetime.fromisoformat(data['last_login'])
        return cls(**data)
    
    def to_string(self) -> str:
        """将用户信息转换为字符串格式"""
        return f"{self.username},{self.password_hash},{self.role},{self.student_id}"
    
    @classmethod
    def from_string(cls, line: str) -> 'User':
        """从字符串创建用户对象"""
        parts = line.strip().split(',')
        if len(parts) != 4:
            raise ValueError("用户数据格式错误")
        return cls(parts[0], parts[1], parts[2], parts[3])
    
    def __str__(self):
        return f"用户名: {self.username}, 角色: {self.role}, 对应学号: {self.student_id}"
    
    @staticmethod
    def hash_password(password: str) -> str:
        """对密码进行哈希处理"""
        return hashlib.sha256(password.encode()).hexdigest()
    
    @staticmethod
    def verify_password(password: str, password_hash: str) -> bool:
        """验证密码"""
        return User.hash_password(password) == password_hash
    
    def update_last_login(self):
        """更新最后登录时间"""
        self.last_login = datetime.now()


@dataclass
class SystemConfig:
    """系统配置类"""
    data_file: str = "students.txt"
    courses_file: str = "courses.txt"
    grades_file: str = "grades.txt"
    users_file: str = "users.txt"
    backup_dir: str = "backups"
    log_file: str = "system.log"
    max_backup_files: int = 10
    auto_save_interval: int = 30  # 秒
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'data_file': self.data_file,
            'courses_file': self.courses_file,
            'grades_file': self.grades_file,
            'users_file': self.users_file,
            'backup_dir': self.backup_dir,
            'log_file': self.log_file,
            'max_backup_files': self.max_backup_files,
            'auto_save_interval': self.auto_save_interval
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'SystemConfig':
        """从字典创建对象"""
        return cls(**data)
